#include "ImageIO.h"
#include "Image.h"

#include <fstream>

using namespace std;

#pragma pack(push, 1)
/* tga header */
struct TGAHeader
{
    unsigned char   mIdLength;          /* size of image id */
    unsigned char   mColormapType;      /* 1 is has a colormap */
    unsigned char   mImageType;         /* compression type */

    short   mColorMapOrigin;     /* colormap origin */
    short   mColorMapLength;          /* colormap length */
    unsigned char   mColorMapSize;            /* colormap size */

    short   mXOrigin;           /* bottom left x coord origin */
    short   mYOrigin;           /* bottom left y coord origin */

    short   mWidth;              /* picture width (in pixels) */
    short   mHeight;             /* picture height (in pixels) */

    unsigned char   mPixelDepth;        /* bits per pixel: 8, 16, 24 or 32 */
    unsigned char   mImageDescriptor;   /* 24 bits = 0x00; 32 bits = 0x80 */

};
#pragma pack(pop)

ImageIO::ImageIO()
{
}

ImageIO::~ImageIO()
{
}

bool ImageIO::load(const char* pFileName, Image& pImage) const
{
	ifstream	lImageFile(pFileName, ios::in | ios::binary);

	if (lImageFile.is_open())
	{
		TGAHeader	lHeader;

		lImageFile.read((char*)&lHeader, sizeof(lHeader));
		if (lHeader.mPixelDepth == 24)
		{
			unsigned char	lPixel[3];
			Image::Color	lColor;

			pImage.setDimensions(lHeader.mWidth, lHeader.mHeight);

			for (short lY=0 ; lY<lHeader.mHeight ; lY++)
			{
				for (short lX=0 ; lX<lHeader.mWidth ; lX++)
				{
					lImageFile.read((char*)lPixel, 3);
					lColor.r = lPixel[2]/255.f;
					lColor.g = lPixel[1]/255.f;
					lColor.b = lPixel[0]/255.f;

					pImage.setValue(lX, lY, lColor);
				}
			}


			return true;
		}
		else if (lHeader.mPixelDepth == 32)
		{
			unsigned char	lPixel[3];
			Image::Color	lColor;

			pImage.setDimensions(lHeader.mWidth, lHeader.mHeight);

			for (short lY=0 ; lY<lHeader.mHeight ; lY++)
			{
				for (short lX=0 ; lX<lHeader.mWidth ; lX++)
				{
					lImageFile.read((char*)lPixel, 4);
					lColor.r = lPixel[2]/255.f;
					lColor.g = lPixel[1]/255.f;
					lColor.b = lPixel[0]/255.f;

					pImage.setValue(lX, lY, lColor);
				}
			}
			return true;
		}
		return false;
	}

	return false;
}

/*********************************************************************/
bool ImageIO::save(const char* pFileName, const Image& pImage) const
{
	if (pImage.getWidth()>0 && pImage.getHeight()>0)
	{
		ofstream	lImageFile(pFileName, ios::out | ios::binary);

		if (lImageFile.is_open())
		{
			TGAHeader		lHeader;
			unsigned char	lPixel[3];
			Image::Color	lColor;

			memset(&lHeader, 0, sizeof(TGAHeader));
			lHeader.mImageType = 2;
			lHeader.mPixelDepth = 24;
			lHeader.mWidth = pImage.getWidth();
			lHeader.mHeight = pImage.getHeight();
			lImageFile.write((char*)&lHeader, sizeof(lHeader));

			for (short lY=0 ; lY<lHeader.mHeight ; lY++)
			{
				for (short lX=0 ; lX<lHeader.mWidth ; lX++)
				{
					lColor = pImage.getValue(lX,lHeader.mHeight-lY-1);
					lPixel[0] = (unsigned char) min(lColor.r*255.f, 255.f);
					lPixel[1] = (unsigned char) min(lColor.g*255.f, 255.f);
					lPixel[2] = (unsigned char) min(lColor.b*255.f, 255.f);
					lImageFile.write((char*)lPixel, 3);
				}
			}

			return true;
		}
	}

	return false;
}